home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-07-03 | 8.4 KB | 313 lines | [TEXT/PJMM] |
- {****************************************************}
- {}
- { CFSDirFieldPane.p }
- {}
- { Pane methods for the direction field pane. }
- {}
- { Copyright © 1995, Patrick Hew. All rights reserved. }
- {}
- {****************************************************}
-
-
- unit CFSDirFieldPane;
-
- interface
-
- uses
- TCL, FSIntf;
-
- implementation
-
-
- const
- kPlotSpace = 16;
- kFlightCircRad = kPlotSpace div 4;
-
- const
- kRefreshFreq = 10;
-
-
- { Coordinate conversion functions. }
-
- function PanehFromBank (aBank: Real): Integer;
-
- begin { PanevFromBank }
- PanehFromBank := Trunc(kDirFieldHalfWidth + aBank * kBankToFrame);
- end; { PanevFromBank }
-
- function BankFromPaneh (aPaneh: Integer): Real;
-
- begin { BankFromPaneh }
- BankFromPaneh := (aPaneh - kDirFieldHalfWidth) * kFrameToBank;
- end; { BankFromPaneh }
-
- function PanevFromAOA (aAOA: Real): Integer;
-
- begin { PanehFromAOA }
- PanevFromAOA := Trunc(kDirFieldHalfHeight - aAOA * kAOAToFrame);
- end; { PanehFromAOA }
-
- function AOAFromPanev (aPanev: Integer): Real;
-
- begin { AOAFromPanev }
- AOAFromPanev := -(aPanev - kDirFieldHalfHeight) * kFrameToAOA;
- end; { AOAFromPanev }
-
-
- { IFSDirFieldPane }
- {}
- { Post: Our direction field pane has been initialized. }
-
- procedure CFSDirFieldPane.IFSDirFieldPane (anEnclosure: CView; aSupervisor: CBureaucrat; aWidth, aHeight, aHEncl, aVEncl: integer; aHSizing, aVSizing: SizingOption);
-
- begin { IFSDirFieldPane }
- IPane(anEnclosure, aSupervisor, aWidth, aHeight, aHEncl, aVEncl, aHSizing, aVSizing);
-
- fBankStable := TRUE;
- fAOAStable := TRUE;
-
- oldBank := 0;
- oldAOA := 0;
- currBank := 0;
- currAOA := 0;
-
- end; { IFSDirFieldPane }
-
-
- { Draw }
- {}
- { Post: The part of the direction field given by area has been drawn, }
- { and the current bank and AOA marked in. }
-
- procedure CFSDirFieldPane.Draw (var area: Rect);
-
- var
- yawbankCount, AOACount: Integer; { Don't need LongInt (?) }
- theBankRate, theAOARate: Real;
- plotBankRate, plotAOARate: Integer;
- arrowHor, arrowVer: Integer;
-
- plotBank, plotAOA: Integer;
- flightRect: Rect;
-
- begin { Draw }
- ShowPen;
- PenSize(1, 1);
- PenMode(PatCopy);
-
- { Erase the old flight circle }
-
- plotBank := PanehFromBank(oldBank);
- plotAOA := PanevFromAOA(oldAOA); { Quickdraw coordinates are down positive. }
- SetRect(flightRect, plotBank - kFlightCircRad, plotAOA - kFlightCircRad, plotBank + kFlightCircRad, plotAOA + kFlightCircRad);
-
- PenPat(White);
- FrameOval(flightRect);
-
- { Draw the direction field. }
-
- for yawbankCount := area.left div kPlotSpace - 1 to area.right div kPlotSpace + 1 do begin
- for AOACount := area.top div kPlotSpace - 1 to area.bottom div kPlotSpace + 1 do begin
- { Note that drawing is done with +ve right, down }
- { whereas we are drawing a graph with +ve right, up. }
-
- GetDirection(BankFromPaneh(yawbankCount * kPlotSpace), AOAFromPanev(AOACount * kPlotSpace), theBankRate, theAOARate);
-
- { Tweak the arrows so that they fit. }
- { Arrows are only to scale up to kPlotSpace. }
-
- plotBankRate := Trunc(theBankRate * kBankToFrame) div 4;
- plotAOARate := Trunc(theAOARate * kAOAToFrame) div 4;
-
- if plotBankRate > kPlotSpace then begin
- plotBankRate := kPlotSpace;
- end { if }
- else if plotBankRate < -kPlotSpace then begin
- plotBankRate := -kPlotSpace;
- end; { else }
-
- if plotAOARate > kPlotSpace then begin
- plotAOARate := kPlotSpace;
- end { if }
- else if plotAOARate < -kPlotSpace then begin
- plotAOARate := -kPlotSpace;
- end; { else }
-
- PenPat(Black);
- MoveTo(yawbankCount * kPlotSpace - plotBankRate div 2, AOACount * kPlotSpace + plotAOARate div 2);
- Line(plotBankRate, -plotAOARate);
-
- if (plotBankRate <> 0) and (plotAOARate <> 0) then begin
- Line(-2 * plotBankRate div Abs(plotBankRate), 0);
- Move(2 * plotBankRate div Abs(plotBankRate), 0);
- Line(0, 2 * plotAOARate div Abs(plotAOARate)); { Note reverse direction }
- end { if }
- else if (plotBankRate <> 0) and (plotAOARate = 0) then begin
- Line(-plotBankRate div Abs(plotBankRate), 1);
- Line(0, -2);
- end { else if }
- else if (plotBankRate = 0) and (plotAOARate <> 0) then begin
- Line(1, plotAOARate div Abs(plotAOARate)); { Note reverse direction }
- Line(-2, 0);
- end; { else if }
-
- end; { for }
- end; { for }
-
- { Draw the new flight circle. }
-
- plotBank := PanehFromBank(currBank);
- plotAOA := PanevFromAOA(currAOA); { Quickdraw coordinates are down positive. }
- SetRect(flightRect, plotBank - kFlightCircRad, plotAOA - kFlightCircRad, plotBank + kFlightCircRad, plotAOA + kFlightCircRad);
-
- FrameOval(flightRect);
-
- end; { Draw }
-
-
- { SetBankStability }
- {}
- { Post: The bank axes have been set to the given stability, }
- { and the plane prepared for redrawing. }
-
- procedure CFSDirFieldPane.SetBankStability (fStable: Boolean);
-
- begin { SetStability }
- fBankStable := fStable;
-
- Refresh;
- end; { SetBankStability }
-
-
- { SetAOAStability }
- {}
- { Post: The AOA axes have been set to the given stability, }
- { and the plane prepared for redrawing. }
-
- procedure CFSDirFieldPane.SetAOAStability (fStable: Boolean);
-
- begin { SetStability }
- fAOAStable := fStable;
-
- Refresh;
- end; { SetAOAStability }
-
-
- { GetDirection }
- {}
- { Post: The bank and AOA rates have been obtained for the }
- { required point in the direction field. }
- { Note: This function is hard coded as a method for the direction }
- { field pane, although in principle of course we can store it as a }
- { method in a dedicated object. It just wasn't worth the effort. }
-
- procedure CFSDirFieldPane.GetDirection (aBank, aAOA: Real; var aBankRate, aAOARate: Real);
-
- begin { GetDirection }
- { Bank }
- if fBankStable then begin
- aBankRate := -aBank;
- end { if }
- else begin
- aBankRate := Sin(aBank * 2);
- end; { else }
-
- { AOA }
- if fAOAStable then begin
- aAOARate := -2 * aAOA;
- end { if }
- else begin
- { Set up the direction field to limit the AOA so that }
- { it cannot exceed ± pi/2, and is hard pushed to }
- { exceed ± pi/4. }
- { Recall that the maximum AOA change which the }
- { stick can exert (per frame) is pi/12. We set it }
- { up so that this rate is met (or exceeded) by ± pi/3. }
-
- if aAOA < -pi / 4 then begin
- aAOARate := -(aAOA + pi / 4) * kRefreshFreq;
- end { if }
- else if aAOA > pi / 4 then begin
- aAOARate := -(aAOA - pi / 4) * kRefreshFreq;
- end
- else begin
- aAOARate := Sin(aAOA * 4);
- end; { else }
- end; { else }
-
- end; { GetDirection }
-
-
- { GetCurrPosition }
- {}
- { Post: The current bank and AOA values have been obtained. }
-
- procedure CFSDirFieldPane.GetCurrPosition (var aCurrBank, aCurrAOA: Real);
-
- begin { GetCurrPosition }
- aCurrBank := currBank;
- aCurrAOA := currAOA;
- end; { GetCurrPosition }
-
-
- { SetCurrPosition }
- {}
- { Post: The current bank and AOA values have been set. }
- { Note: This is used in "autopilot" mode to ensure that we fly straight and level. }
-
- procedure CFSDirFieldPane.SetCurrPosition (aCurrBank, aCurrAOA: Real);
-
- var
- plotBank, plotAOA: Integer;
- flightRect: Rect;
-
- begin { SetCurrPosition }
- oldBank := currBank;
- oldAOA := currAOA;
- currBank := aCurrBank;
- currAOA := aCurrAOA;
-
- plotBank := PanehFromBank(oldBank);
- plotAOA := PanevFromAOA(oldAOA);
- SetRect(flightRect, plotBank - kFlightCircRad, plotAOA - kFlightCircRad, plotBank + kFlightCircRad, plotAOA + kFlightCircRad);
- RefreshRect(flightRect);
-
- plotBank := PanehFromBank(currBank);
- plotAOA := PanevFromAOA(currAOA);
- SetRect(flightRect, plotBank - kFlightCircRad, plotAOA - kFlightCircRad, plotBank + kFlightCircRad, plotAOA + kFlightCircRad);
- RefreshRect(flightRect);
-
- end; { SetCurrPosition }
-
-
- { UpdatePosition }
- {}
- { Post: The current position in the direction field has been updated, }
- { including the external input. }
-
- procedure CFSDirFieldPane.UpdatePosition (aBankChange, aAOAChange: Real);
-
- var
- theBankRate, theAOARate: Real;
- theNewBank, theNewAOA: Real;
-
- begin { UpdatePosition }
- GetDirection(currBank, currAOA, theBankRate, theAOARate);
-
- { We have rotational degeneracy in the case of bank. }
- theNewBank := currBank + aBankChange + theBankRate / kRefreshFreq;
-
- if (currBank < pi) and (theNewBank > pi) then begin
- theNewBank := theNewBank - 2 * pi;
- end { if }
- else if (currBank > -pi) and (theNewBank < -pi) then begin
- theNewBank := theNewBank + 2 * pi;
- end; { else }
-
- theNewAOA := currAOA + aAOAChange + theAOARate / kRefreshFreq;
-
- SetCurrPosition(theNewBank, theNewAOA);
- end; { UpdatePosition }
-
-
- end. { CFSDirFieldPane }